#include <LogFile.h>

namespace AsyncLogger {
	LogFile::LogFile(const std::string logDirPath, const std::string& basename, off_t rollSize, bool threadSafe, int flushInterval, int checkEveryN)
		:logDirPath_(logDirPath), basename_(basename), rollSize_(rollSize), flushInterval_(flushInterval), checkEveryN_(checkEveryN)
	{
		if (threadSafe) {
			mutex_ = std::move(std::unique_ptr<std::mutex>(new std::mutex));
		}
		else {
			mutex_ = nullptr;
		}
		count_ = 0;
		lastFlush_ = ::time(nullptr);
		rollFile();
	}

	void LogFile::flush()
	{
		file_->flush();
	}

	void LogFile::rollFile()
	{
		long long now;
		std::string filename = getLogFilename(now);
		std::string fileFullName = logDirPath_ + filename;
		std::cout << fileFullName << std::endl;
		time_p start = now / kRollPerSeconds_ * kRollPerSeconds_; // now/kRollPerSeconds_得到周期的起始点，*kRollPerSeconds_得到周期起始点的时间戳
		count_ = 0;
		lastFlush_ = now;
		lastRoll_ = now;
		startOfPeriod_ = start;
		file_ = std::move(std::unique_ptr<FileUtil::AppendFile>(new FileUtil::AppendFile(fileFullName)));
	}

	void LogFile::append(const char* logline, int len)
	{
		if (mutex_) {
			std::lock_guard<std::mutex> lock(*mutex_);
			append_unlocked(logline, len);
		}
		else {
			append_unlocked(logline, len);
		}
	}

	void LogFile::append_unlocked(const char* logline, size_t len)
	{
		file_->append(logline, len);
		int size = file_->writtenBytes();
		// 文件滚动，滚动条件为 1、时间 2、文件大小，满足其中一种即滚动文件
		if (file_->writtenBytes() > rollSize_) { // 根据写入的大小进行滚动
			std::cout << basename_ << " has write bytes: " << file_->writtenBytes() << " rollsize: " << rollSize_ << std::endl;
			rollFile();
		}
		else {
			++count_;
			if (count_ >= checkEveryN_)
			{
				count_ = 0;
				time_p now = getTimestamp(); // 得到时间戳，精度s
				time_p thisPeriod = now / kRollPerSeconds_ * kRollPerSeconds_;
				if (thisPeriod != startOfPeriod_) { // 根据时间进行滚动
					rollFile();
				}
				else if (now - lastFlush_ > flushInterval_) {
					flush();
					lastFlush_ = now;
				}
			}
		}
	}

	LogFile::time_p LogFile::getTimestamp()
	{
		return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
	}

	std::string LogFile::getLogFilename(time_p& now)
	{
		std::string filename;
		std::string hostname = FileUtil::getHostname(); // 主机名
#ifdef  _WIN32
		DWORD pid = GetCurrentProcessId(); // processId
#else
		pid_t pid = getpid();
#endif //  _WIN32
		auto clock_now = std::chrono::system_clock::now();
		now = std::chrono::duration_cast<std::chrono::seconds>(clock_now.time_since_epoch()).count(); // 得到时间戳，精度s
		auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(clock_now.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(clock_now.time_since_epoch()).count(); // 获取毫秒
		std::time_t tt = std::chrono::system_clock::to_time_t(clock_now); // 解析时间
		std::tm* ptm = std::localtime(&tt);
		char buf[64] = { 0 };
		sprintf(buf, "%d%0.2d%0.2d-%0.2d%0.2d%0.2d-%lld", 1900 + ptm->tm_year, 1 + ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, ms);
		// 文件格式：程序名.时间.主机名.pid.log
		filename = basename_ + "." + buf + "." + hostname + "." + std::to_string(pid) + ".log";
		return filename;
	}
}